package org.example.analysis.service;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import lombok.extern.slf4j.Slf4j;
import org.example.analysis.model.MethodCallInfo;
import org.example.analysis.service.analyzer.ClassAnalyzer;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 方法调用分析器 - 只分析项目内的方法调用
 */
@Slf4j
public class MethodCallAnalyzer {
    private final String sourceRoot;
    private final Map<String, MethodCallInfo> methodCallCache = new HashMap<>();
    private final int maxDepth;
    private final JavaParser javaParser;

    public MethodCallAnalyzer(String sourceRoot, int maxDepth) {
        this.sourceRoot = sourceRoot;
        this.maxDepth = maxDepth;
        this.javaParser = new JavaParser();
    }

    /**
     * 分析指定方法的调用链
     *
     * @param sourceDir 源代码目录
     * @param className 类名
     * @param methodName 方法名
     * @param parameterTypes 参数类型列表
     * @return 方法调用信息
     */
    public MethodCallInfo analyzeMethodCalls(String sourceDir, String className, String methodName, List<String> parameterTypes) {
        String methodSignature = buildMethodSignature(className, methodName, parameterTypes);
        
        // 检查缓存
        if (methodCallCache.containsKey(methodSignature)) {
            return methodCallCache.get(methodSignature);
        }

        try {
            // 创建方法调用信息对象
            MethodCallInfo methodCallInfo = new MethodCallInfo()
                    .setClassName(className)
                    .setMethodName(methodName)
                    .setParameterTypes(parameterTypes)
                    .setDepth(0);

            // 分析方法调用
            analyzeMethodCallsRecursively(methodCallInfo, new HashSet<>(), 0);

            // 缓存结果
            methodCallCache.put(methodSignature, methodCallInfo);
            return methodCallInfo;
        } catch (Exception e) {
            log.error("分析方法调用链失败: {}", methodSignature, e);
            return null;
        }
    }

    /**
     * 递归分析方法调用
     */
    private void analyzeMethodCallsRecursively(MethodCallInfo currentMethod, Set<String> visitedMethods, int depth) {
        if (depth >= maxDepth || visitedMethods.contains(currentMethod.getMethodSignature())) {
            return;
        }

        visitedMethods.add(currentMethod.getMethodSignature());

        try {
            // 查找方法声明
            File sourceFile = findSourceFile(currentMethod.getClassName());
            if (sourceFile == null || !sourceFile.exists()) {
                log.debug("源文件不存在: {}", sourceFile);
                return;
            }

            CompilationUnit cu = ClassAnalyzer.parse(sourceFile, javaParser);
            if (cu == null) {
                log.debug("解析源文件失败: {}", sourceFile);
                return;
            }

            // 访问方法声明
            cu.accept(new MethodVisitor(currentMethod, depth + 1), null);

        } catch (Exception e) {
            log.error("递归分析方法调用失败: {}", currentMethod.getMethodSignature(), e);
        }
    }

    /**
     * 方法访问器
     */
    private class MethodVisitor extends VoidVisitorAdapter<Void> {
        private final MethodCallInfo parentMethod;
        private final int currentDepth;

        public MethodVisitor(MethodCallInfo parentMethod, int currentDepth) {
            this.parentMethod = parentMethod;
            this.currentDepth = currentDepth;
        }

        @Override
        public void visit(MethodDeclaration md, Void arg) {
            super.visit(md, arg);

            // 检查是否是目标方法
            if (!isTargetMethod(md, parentMethod)) {
                return;
            }

            // 设置方法位置信息
            parentMethod.setStartLine(md.getBegin().get().line);
            parentMethod.setEndLine(md.getEnd().get().line);
            parentMethod.setComment(md.getComment().map(c -> c.getContent()).orElse(""));

            // 访问方法调用表达式
            md.accept(new MethodCallVisitor(parentMethod, currentDepth), null);
        }
    }

    /**
     * 方法调用表达式访问器
     */
    private class MethodCallVisitor extends VoidVisitorAdapter<Void> {
        private final MethodCallInfo parentMethod;
        private final int currentDepth;

        public MethodCallVisitor(MethodCallInfo parentMethod, int currentDepth) {
            this.parentMethod = parentMethod;
            this.currentDepth = currentDepth;
        }

        @Override
        public void visit(MethodCallExpr methodCall, Void arg) {
            super.visit(methodCall, arg);

            try {
                // 获取方法调用的完整限定名
                String calledClassName = null;
                if (methodCall.getScope().isPresent()) {
                    calledClassName = methodCall.getScope().get().toString();
                }
                
                // 如果无法获取类名，跳过
                if (calledClassName == null) {
                    return;
                }

                String calledMethodName = methodCall.getNameAsString();
                
                // 获取参数类型
                List<String> calledParameterTypes = methodCall.getArguments().stream()
                    .map(expr -> expr.getClass().getSimpleName())
                    .collect(Collectors.toList());

                // 创建被调用方法的信息对象
                MethodCallInfo calledMethod = new MethodCallInfo()
                        .setClassName(calledClassName)
                        .setMethodName(calledMethodName)
                        .setParameterTypes(calledParameterTypes)
                        .setDepth(currentDepth);

                // 添加到调用列表
                parentMethod.getCalledMethods().add(calledMethod);
                
                // 递归分析被调用的方法
                if (isProjectClass(calledClassName)) {
                    analyzeMethodCallsRecursively(calledMethod, new HashSet<>(), currentDepth);
                }
            } catch (Exception e) {
                log.debug("解析方法调用失败: {}", methodCall, e);
            }
        }
    }

    /**
     * 检查是否是目标方法
     */
    private boolean isTargetMethod(MethodDeclaration md, MethodCallInfo targetMethod) {
        if (!md.getNameAsString().equals(targetMethod.getMethodName())) {
            return false;
        }

        List<String> parameterTypes = md.getParameters().stream()
                .map(p -> p.getType().asString())
                .collect(Collectors.toList());

        return parameterTypes.equals(targetMethod.getParameterTypes());
    }

    /**
     * 检查是否是项目内的类
     */
    private boolean isProjectClass(String className) {
        File sourceFile = findSourceFile(className);
        return sourceFile != null && sourceFile.exists();
    }

    /**
     * 根据类名查找源文件
     */
    private File findSourceFile(String className) {
        String relativePath = className.replace('.', File.separatorChar) + ".java";
        return new File(sourceRoot, relativePath);
    }

    /**
     * 构建方法签名
     */
    private String buildMethodSignature(String className, String methodName, List<String> parameterTypes) {
        StringBuilder signature = new StringBuilder();
        signature.append(className).append("#").append(methodName).append("(");
        if (parameterTypes != null && !parameterTypes.isEmpty()) {
            signature.append(String.join(", ", parameterTypes));
        }
        signature.append(")");
        return signature.toString();
    }
} 